package com.hxzy.tms.service.impl;

import java.security.SecureRandom;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hxzy.tms.SessionHolder;
import com.hxzy.tms.dao.UserDao;
import com.hxzy.tms.entity.User;
import com.hxzy.tms.service.ServiceResult;
import com.hxzy.tms.service.UserService;

public class DefaultUserService implements UserService {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private UserDao userDao;

    public ServiceResult<User> read(long id) {
        User user = userDao.read(id);
        return new ServiceResult<User>(1, user);
    }

    public ServiceResult<User> getUser(String hash, String ip) {
        if (StringUtils.isBlank(hash) || StringUtils.isBlank(ip)) {
            return new ServiceResult<User>(1, null);
        }
        if (SessionHolder.get() != null) {
            return new ServiceResult<User>(1, SessionHolder.get());
        }

        if (StringUtils.isEmpty(ip) || StringUtils.isEmpty(hash)) {
            return new ServiceResult<User>(1, null);
        }

        Map<String, Object> param = new HashMap<String, Object>();
        param.put("hash", hash);
        param.put("gmt_hash_expires", (System.currentTimeMillis() / 1000));
        List<User> users = userDao.read("from User where hash = :hash and gmtHashExpires > :gmt_hash_expires ", param);
        if (users.isEmpty()) {
            return new ServiceResult<User>(1, null);
        }

        User user = users.get(0);

        if (!ip.equals(user.getIpLogin())) { // 如果换 ip 了就当没有登录过啦，TODO 要清空 hash
            return new ServiceResult<User>(1, null);
        }

        User userInSession = new User();
        userInSession.setId(user.getId());
        userInSession.setNickname(user.getNickname());
        return new ServiceResult<User>(1, userInSession);
    }

    public User login(String username, String passwd, String ip) {
        if (StringUtils.isBlank(username) || StringUtils.isBlank(passwd) || StringUtils.isBlank(ip)) {
            return null;
        }

        try {
            // 1. 先尝试邮箱登录；
            Map<String, Object> param = new HashMap<String, Object>();
            param.put("email", username);
            List<User> users = userDao.read("from User where email = :email", param);
            if (users.isEmpty()) {
                // 2. 再尝试账号密码登录
                param = new HashMap<String, Object>();
                param.put("username", username);
                users = userDao.read("from User where username = :username", param);
            }

            if (users.isEmpty() || users.size() > 1) {
                return null;
            }
            if (users.size() > 1) {
                logger.error("{} 匹配到 {} 条用户记录 {} ", username, users.size());
                return null;
            }

            User user = users.get(0);
            if (user == null || !user.getPasswd().equals(DigestUtils.sha256Hex((user.getSalt() + passwd).getBytes()))) { // 加密比对
                logger.error("{} 尝试登录但密码错误", username);
                return null;
            }

            // 2. 更新登录时间和登录ip
            long now = (System.currentTimeMillis() / 1000);
            user.setGmtLogin(now);
            user.setIpLogin(ip);
            user.setGmtModified(now);

            userDao.saveOrUpdate(user);

            // tx.commit();

            // user.setPasswd(null); // 敏感数据脱敏处理
            User userInSession = new User();
            userInSession.setId(user.getId());
            userInSession.setNickname(user.getNickname());

            SessionHolder.set(userInSession);

            return userInSession;
        } catch (Exception e) {
            logger.error("登陆失败", e);
        }

        return null;
    }

    public ServiceResult<User> register(String email, String passwd, String nickname, String realname, long mobile,
            String vercode, String ip) {
        // 1. 检查邮箱是否重复
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("email", email);
        List<User> users = userDao.read("from User where email = :email", param);
        if (!users.isEmpty()) {
            return new ServiceResult<User>(-1, null, "邮箱已存在"); // 邮箱已存在
        }

        // 检查手机号是否存在
        param = new HashMap<String, Object>();
        param.put("phone", mobile);
        users = userDao.read("from User where phone = :phone", param);
        if (!users.isEmpty()) {
            return new ServiceResult<User>(-2, null, "手机号已存在"); // 手机号
        }

        // 因为是使用 email 注册
        String randomUsername = this.generateUsername(ip).data;
        if (randomUsername == null) {
            return new ServiceResult<User>(-3, null, "自动创建用户失败"); // 生成自动的用户名失效
        }
        User user = new User();
        user.setSalt(createSalt());
        user.setUsername(randomUsername);
        user.setEmail(email);
        user.setPasswd(DigestUtils.sha256Hex((user.getSalt() + passwd).getBytes()));
        user.setNickname(nickname);
        user.setRealname(realname);
        user.setPhone(mobile);
        user.setGmtCreate(System.currentTimeMillis() / 1000);
        user.setGmtModified(user.getGmtCreate());
        user.setIpReg(ip);
        user.setStatus(1L);
        user.setRoot(0);

        userDao.create(user);

        logger.info("新用户注册 {}", user.getUsername());

        return new ServiceResult<User>(1, null, "注册成功");
    }

    public ServiceResult<String> generateUsername(String ip) {
        int i = 3;

        while (i-- > 0) {
            String username = "u" + (System.currentTimeMillis() + (new Random().nextInt(10000)));
            Map<String, Object> param = new HashMap<String, Object>();
            param.put("username", username);
            List<User> users = userDao.read("from User where username = :username", param);
            if (users.isEmpty()) {
                return new ServiceResult<String>(1, username); // 邮箱已存在
            }
        }
        return null;
    }

    public void logout() {
        if (SessionHolder.get() != null) {
            User user = userDao.read(User.class, SessionHolder.get().getId());
            user.setHash("");
            user.setGmtHashExpires(0L);
            userDao.saveOrUpdate(user);

            SessionHolder.clear();
        }
    }

    public ServiceResult<String> generateSessionHash(String ip) {
        // if (SessionHolder.get() != null) {
        // return new ServiceResult<String>(-1);
        // }
        long sessionUser = SessionHolder.get().getId();
        int s = RandomUtils.nextInt(10000, 99999); // 随机数

        String hash = DigestUtils.sha256Hex((s + ip).getBytes());
        User user = userDao.read(User.class, sessionUser);
        user.setHash(hash);
        long hashExpires = (System.currentTimeMillis() / 1000) + 7 * 24 * 60 * 60;
        user.setGmtHashExpires(hashExpires); // 超时时间是 7 天
        if (userDao.update(user) == 1) {
            return new ServiceResult<String>(1, hash);
        } else {
            return new ServiceResult<String>(-2, null, "数据库错误");
        }
    }

    private String createSalt() {
        Random ranGen = new SecureRandom();
        byte[] aesKey = new byte[32];
        ranGen.nextBytes(aesKey);
        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < aesKey.length; i++) {
            String hex = Integer.toHexString(0xff & aesKey[i]);
            if (hex.length() == 1)
                hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    }

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

}
